using Devil;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;

namespace GameToolkit.UI
{
    public enum EFixSymbolLevel
    {
        Low, // 0.1
        Middle, // 0.2
        High, // 0.4
        DontFix, // 0.8
    }

    public class RichText : Text
    {
        static readonly ObjectPool<EmojiButton> btnPool = new ObjectPool<EmojiButton>(32, () => new EmojiButton());
        static readonly string prop_rotate = "rotate=";
        static readonly string prop_dx = "dx=";
        static readonly string prop_dy = "dy=";
        static readonly string prop_click = "click="; //
        static readonly string prop_size = "scale="; // 
        static readonly string prop_ratio = "ratio="; // 0.3
        static readonly string prop_flip = "flip="; // X,Y
        static readonly Regex emojiPattern = new Regex(@"<quad(=[a-zA-Z0-9/=_ \-\.]*)?(/)?>");
        //static readonly Regex propPattern = new Regex(@"(rotate|dx|dy|click|scale)=[0-9]+(\.[0-9]+)?(?:( |  |/|>))");
        //static readonly Regex emojiPattern = new Regex(@"<quad=([a-zA-Z0-9_]+.)?[a-zA-Z0-9_]+[ a-z0-9\-=.]*( /)?>");

        //static Material sDefaultMat;

#if UNITY_EDITOR
        [UnityEditor.MenuItem("GameObject/UI/Rich Text")]
        static void CreateRichText()
        {
            var sel = UnityEditor.Selection.activeGameObject;
            var parent = sel == null ? null : sel.transform as RectTransform;
            var can = parent == null ? null : parent.GetComponentInParent<Canvas>();

            if (can == null)
            {
                var go = new GameObject("Canvas", new System.Type[] { typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster) });
                can = go.GetComponent<Canvas>();
                can.renderMode = RenderMode.ScreenSpaceOverlay;
                parent = can.transform as RectTransform;
                UnityEditor.Undo.RegisterCreatedObjectUndo(go, "NewRichText");
            }
            var txt = new GameObject("Rich Text", new System.Type[] { typeof(RichText) });
            txt.transform.SetParent(parent, false);
            UnityEditor.Undo.RegisterCreatedObjectUndo(txt, "NewRichText");
        }
#endif

        public struct EmojiResult
        {
            public Sprite sprite;
            public int texIndex;
            public float rotate;
        }

        public struct Emoji
        {
            public int charIndex;
            public string spriteName;
            public EmojiAnims.Anim anim;
            public bool raw;
            public float rotate;
            public Vector2 offset;
            public EAxis flip;
            public float scale;
            public int btnId;
            public float fixRatio; // -1: 自动，0：默认， > 0: 自定义

            public float finalRotate;
            public EmojiResult result;

            public void GetFrame(float time, ref EmojiResult result)
            {
                if (anim != null)
                {
                    var f = anim.GetFrame(time);
                    spriteName = f.m_Sprite;
                    result.rotate = this.rotate + f.m_Rotate;
                }
                else
                {
                    result.rotate = this.rotate;
                }
            }
        }

        public class EmojiButton
        {
            public int emojiIndex;
            public int clickId;
            public Rect rect;
        }

#pragma warning disable CS0649
        //[SerializeField]
        //SpriteAtlas m_Atlas;
        //public SpriteAtlas Atlas
        //{
        //    get
        //    {
        //        return m_Atlas;
        //    }
        //    set
        //    {
        //        if (m_Atlas != value)
        //        {
        //            m_Atlas = value;
        //            if (mSprites != null)
        //            {
        //                foreach (var spr in mSprites.Values)
        //                {
        //                    GlobalUtil.Destroy(spr);
        //                }
        //                mSprites.Clear();
        //            }
        //            if (mHasSprite)
        //                SetVerticesDirty();
        //        }
        //    }
        //}
        [SerializeField]
        string m_DefaultAtlasFolder = "Assets/ArtRes/Sprites/";
        [SerializeField]
        string m_DefaultAtlas = "Common";
        //[SerializeField]
        //bool m_AutoAtlasFolder = true;

        [SerializeField]
        EmojiAnims m_Anims;
        [SerializeField]
        bool m_SupportEmoji = true;

        [SerializeField]
        EFixSymbolLevel m_FixSymbolLevel;

        int mTexId;
        int mTexId2;
        List<Emoji> mEmojies = new List<Emoji>();

        readonly UIVertex[] m_TempVerts = new UIVertex[4]; // left-up,right-up,right-down,left-down
        List<string> mEmojiProperties = new List<string>();

        List<EmojiButton> mEmojiBtns = new List<EmojiButton>();

        //[SerializeField]
        //int m_ShareMaterialId;

        bool mAnimate;
        float mAnimDuration;
        float mTimer;
        float mTime;
        //Material mEmojiMat;
        //bool mHasSprite;
        float mFixEmojiVerticle;
#pragma warning restore

        //Dictionary<string, Sprite> mSprites;

        Shader mEmojiShader;

        IMaterialInstance mDefaultMat;

        //public override Material defaultMaterial
        //{
        //    get
        //    {
        //        //if (sDefaultMat == null)
        //        //{
        //        //    var shader = Shader.Find("DevilTeam/EmojiFont");
        //        //    if (shader != null)
        //        //    {
        //        //        sDefaultMat = new Material(shader);
        //        //        sDefaultMat.hideFlags |= HideFlags.DontSave;
        //        //    }
        //        //}

        //        if (mDefaultMat != null)
        //            return mDefaultMat.material;
        //        else
        //            return base.defaultMaterial;
        //    }
        //}

        public override Material material
        {
            get
            {
                var mat = m_Material;
                if (mat == null)
                {
                    if (mDefaultMat != null)
                        mat = mDefaultMat.material;
                    else
                        mat = defaultMaterial;
                }
                return mat;
            }
            set
            {
                if (m_Material == value)
                    return;
                m_Material = value;
                SetMaterialDirty();
            }
        }

        void ClearEmojiBtns()
        {
            for (int i = 0; i < mEmojiBtns.Count; i++)
            {
                var btn = mEmojiBtns[i];
                btnPool.Add(btn);
            }
            mEmojiBtns.Clear();
        }

        public override string text
        {
            get
            {
                return m_Text;
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    if (string.IsNullOrEmpty(m_Text))
                        return;
                    m_Text = "";
                    if (isActiveAndEnabled)
                    {
                        GetEmojies();
                        SetVerticesDirty();
                    }
                }
                else if (m_Text != value)
                {
                    mTime = 0;
                    mTimer = 0;
                    m_Text = value;
                    if (isActiveAndEnabled)
                    {
                        GetEmojies();
                        if (!GetEmojiResultsDirty())
                            SetVerticesDirty();
                        SetLayoutDirty();
                    }
                }
            }
        }

        bool ParseEmoji(Match mat, out Emoji emoji)
        {
            mEmojiProperties.Clear();
            var v = mat.Value;
            if (mat.Length < 6 || v[5] != '=')
            {
                emoji = default(Emoji);
                emoji.charIndex = mat.Index;
                return false;
            }
            if (!StringUtil.ParseArray(v, mEmojiProperties, ' ', '<', '>') || mEmojiProperties.Count < 1)
            {
                emoji = default(Emoji);
                emoji.charIndex = mat.Index;
                return false;
            }
            Emoji tmp;
            tmp.result = default;
            tmp.charIndex = mat.Index;
            string src = mEmojiProperties[0].Substring(5);
            var anim = m_Anims == null ? null : m_Anims.GetAnim(src);
            tmp.anim = anim;
            int len = mEmojiProperties.Count;
            bool raw = len > 1 && mEmojiProperties[len - 1] == "/";
            tmp.raw = raw;
            if (raw)
                len--;
            tmp.spriteName = src;
            tmp.rotate = 0;
            tmp.btnId = 0;
            tmp.scale = 1f;
            tmp.fixRatio = -1;
            tmp.flip = EAxis.None;
            tmp.result = default;
            Vector2 offset = Vector2.zero;
            int n;
            float f;
            for (int i = 1; i < len; i++)
            {
                var pro = mEmojiProperties[i];
                if (string.IsNullOrEmpty(pro))
                    continue;
                if (pro.StartsWith(prop_rotate) && Localization.TryParse(pro.Substring(7), out f))
                    tmp.rotate = f;
                else if (pro.StartsWith(prop_dx) && Localization.TryParse(pro.Substring(3), out f))
                    offset.x = f;
                else if (pro.StartsWith(prop_dy) && Localization.TryParse(pro.Substring(3), out f))
                    offset.y = f;
                else if (pro.StartsWith(prop_click) && Localization.TryParse(pro.Substring(6), out n))
                    tmp.btnId = n;
                else if (pro.StartsWith(prop_size) && Localization.TryParse(pro.Substring(6), out f))
                    tmp.scale = f;
                else if (pro.StartsWith(prop_flip) && pro.Length == 6)
                {
                    var axis = pro[5];
                    if (axis == 'x' || axis == 'X')
                        tmp.flip = EAxis.X;
                    else if (axis == 'y' || axis == 'Y')
                        tmp.flip = EAxis.Y;
                }
                else if (pro.StartsWith(prop_ratio))
                {
                    if (Localization.TryParse(pro.Substring(6), out f))
                        tmp.fixRatio = f;
                    else
                        tmp.fixRatio = 0;
                }
            }
            tmp.offset = offset;
            tmp.finalRotate = tmp.rotate;
            emoji = tmp;
            return true;
        }

        void GetEmojies()
        {
            mAnimate = false;
            mAnimDuration = 10;
            mEmojies.Clear();
            ClearEmojiBtns();
            if (!supportRichText || !m_SupportEmoji || string.IsNullOrEmpty(m_DefaultAtlasFolder))
                return;
            MatchCollection matchs = emojiPattern.Matches(m_Text);
            for (int i = 0; i < matchs.Count; i++)
            {
                Match mat = matchs[i];
                Emoji emoji;
                if (!ParseEmoji(mat, out emoji))
                {
                    mEmojies.Add(emoji);
                    continue;
                }
                if (emoji.btnId != 0)
                {
                    var btn = btnPool.Get();
                    btn.rect = default(Rect);
                    btn.emojiIndex = mEmojies.Count;
                    btn.clickId = emoji.btnId;
                    emoji.btnId = mEmojiBtns.Count;
                    mEmojiBtns.Add(btn);
                }
                else
                {
                    emoji.btnId = -1;
                }
                mEmojies.Add(emoji);
                if (emoji.anim != null)
                {
                    mAnimate = true;
                    mAnimDuration = Mathf.Min(mAnimDuration, emoji.anim.m_Duration);
                }
            }
        }

        bool GetEmojiResultsDirty()
        {
            Texture2D tex1 = null, tex2 = null;
            var dirty = false;
            var dirtyMat = false;
            for (int i = 0; i < mEmojies.Count; i++)
            {
                var emoji = mEmojies[i];
                EmojiResult result = emoji.result;
                emoji.GetFrame(mTime, ref result);
                var sprite = GetSprite(emoji.spriteName);
                if (sprite != null)
                {
                    dirty |= sprite != result.sprite;
                    result.sprite = sprite;
                    SetupSprite(sprite, ref tex1, ref tex2, out result.texIndex);
                    emoji.result = result;
                    mEmojies[i] = emoji;
                }
            }
            if (mEmojiShader != null && m_Material == null)
            {
                var matId = MathExt.Hash(tex1 == null ? 0 : tex1.GetInstanceID(), tex2 == null ? 0 : tex2.GetInstanceID());
                var mat = MaterialCache.GetMaterial(mEmojiShader, matId);
                if (mat != null)
                    mat.Retain();
                dirtyMat = mDefaultMat != mat;
                if (mDefaultMat != null)
                    mDefaultMat.Release();
                mDefaultMat = mat;

            }
            var inst = material;
            if (inst != null)
            {
                if (tex1 != null)
                    inst.SetTexture(mTexId, tex1);
                if (tex2 != null)
                    inst.SetTexture(mTexId2, tex2);
            }
            if (dirty)
                SetVerticesDirty();
            if (dirtyMat)
                SetMaterialDirty();
            return dirty;
        }

        public bool SupportEmoji
        {
            get { return m_SupportEmoji; }
            set
            {
                if (m_SupportEmoji != value)
                {
                    m_SupportEmoji = value;
                    GetEmojies();
                    SetVerticesDirty();
                    SetLayoutDirty();
                }
            }
        }

        float GetFontVerticleFixPercent(Font f)
        {
            if (f == null)
                return 0;
            var ascent = (float)f.ascent;
            var s = (float)f.lineHeight;
            return (s - ascent) * 0.5f / s;
        }

        protected override void OnEnable()
        {
            mTexId = Shader.PropertyToID("_EmojiTex");
            mTexId2 = Shader.PropertyToID("_EmojiTex2");
            if (mEmojiShader == null)
                mEmojiShader = Shader.Find("DevilTeam/EmojiFont");
            if (m_SupportEmoji)
            {
                GetEmojies();
                GetEmojiResultsDirty();
            }
            //if(mSprites == null)
            //    mSprites = new Dictionary<string, Sprite>();
            base.OnEnable();
            mFixEmojiVerticle = GetFontVerticleFixPercent(font);
        }

        protected override void OnDisable()
        {
            base.OnDisable();
            //foreach (var spr in mSprites.Values)
            //{
            //    GlobalUtil.Destroy(spr);
            //}
            //mSprites.Clear();
        }

        protected override void OnDestroy()
        {
            if (mDefaultMat != null)
            {
                mDefaultMat.Release();
                mDefaultMat = null;
            }
            base.OnDestroy();
            //            if (mEmojiMat != null)
            //            {
            //#if UNITY_EDITOR
            //                if (!Application.isPlaying)
            //                    DestroyImmediate(mEmojiMat);
            //                else
            //#endif
            //                    Destroy(mEmojiMat);
            //                mEmojiMat = null;
            //            }
        }

        bool mGetSpr;

        void WaitAsset(IAssetPtr ptr, Sprite spr)
        {
            if (!mGetSpr && this != null && isActiveAndEnabled)
            {
                GetEmojiResultsDirty();
            }
        }

        Sprite GetSprite(string spr)
        {
            if (string.IsNullOrEmpty(spr))
                return null;
            string file;
            if (spr.StartsWithIgnoreCase("assets/"))
            {
                file = spr;
            }
            else
            {
                var dot = spr.IndexOf('.');
                string atlas, sprname;
                if (dot == -1)
                {
                    sprname = spr;
                    atlas = m_DefaultAtlas;
                }
                else
                {
                    sprname = spr.Substring(dot + 1);
                    atlas = spr.Substring(0, dot);
                }
                if (sprname.IndexOf('.') == -1)
                    sprname = ParallelUtils.Concat(sprname, ".png");
                if (string.IsNullOrEmpty(atlas))
                    file = NativeFileSystem.Combine(m_DefaultAtlasFolder, sprname);
                else// if (m_AutoAtlasFolder)
                    file = NativeFileSystem.Combine(m_DefaultAtlasFolder, atlas, sprname);
            }
            mGetSpr = true;
            var asset = AssetsUtil.GetAssetAsync<Sprite>(file);
            var s = asset != null && asset.LoadResult == ELoadResult.Success ? asset.Asset as Sprite : null;
            if (asset != null && asset.LoadResult <= ELoadResult.Loading)
                asset.Regist(WaitAsset, null);
            mGetSpr = false;

            //Sprite s = null;
            //if (mSprites.TryGetValue(spr, out s) && s != null)
            //{
            //    return s;
            //}

            return s;
        }


        //void HandleAsset(IAssetPtr ptr, SpriteAtlas atlas)
        //{
        //    if (!mGetSpr && this != null)
        //    {
        //        if (MainThread.IsMainThread)
        //            SetVerticesDirty();
        //        else
        //            MainThread.RunOnMainThread(SetVerticesDirty);
        //    }
        //}

        EmojiButton GetEmojiBtn(Emoji emoji, int emojiIndex)
        {
            if (emoji.btnId < 0 || emoji.btnId >= mEmojiBtns.Count)
                return null;
            var btn = mEmojiBtns[emoji.btnId];
            if (btn.emojiIndex == emojiIndex)
                return btn;
            else
                return null;
        }

        Rect CalculateTempVertsBounds()
        {
            Vector2 center = (m_TempVerts[0].position + m_TempVerts[1].position + m_TempVerts[2].position + m_TempVerts[3].position) * 0.25f;
            Vector2 s1 = m_TempVerts[0].position - m_TempVerts[2].position;
            Vector2 s2 = m_TempVerts[1].position - m_TempVerts[3].position;
            Vector2 size = new Vector2(Mathf.Max(Mathf.Abs(s1.x), Mathf.Abs(s2.x)),
                Mathf.Max(Mathf.Abs(s1.y), Mathf.Abs(s2.y)));
            return new Rect(center - size * 0.5f, size);
        }

        void RotateTempVerts(float angle)
        {
            Quaternion roter = Quaternion.AngleAxis(angle, Vector3.forward);
            Vector3 center = (m_TempVerts[0].position + m_TempVerts[1].position + m_TempVerts[2].position + m_TempVerts[3].position) * 0.25f;
            m_TempVerts[0].position = center + roter * (m_TempVerts[0].position - center);
            m_TempVerts[1].position = center + roter * (m_TempVerts[1].position - center);
            m_TempVerts[2].position = center + roter * (m_TempVerts[2].position - center);
            m_TempVerts[3].position = center + roter * (m_TempVerts[3].position - center);
        }

        void MoveTempVerts(Vector3 offset)
        {
            m_TempVerts[0].position += offset;
            m_TempVerts[1].position += offset;
            m_TempVerts[2].position += offset;
            m_TempVerts[3].position += offset;
        }

        void ScaleTempVerts(Vector2 anchor, float scale)
        {
            Vector3 center;//= (m_TempVerts[0].position + m_TempVerts[1].position + m_TempVerts[2].position + m_TempVerts[3].position) * 0.25f;
            center.x = m_TempVerts[0].position.x + (m_TempVerts[1].position.x - m_TempVerts[0].position.x) * anchor.x;
            center.y = m_TempVerts[3].position.y + (m_TempVerts[0].position.y - m_TempVerts[3].position.y) * anchor.y;
            center.z = m_TempVerts[0].position.z;
            m_TempVerts[0].position = center + (m_TempVerts[0].position - center) * scale;
            m_TempVerts[1].position = center + (m_TempVerts[1].position - center) * scale;
            m_TempVerts[2].position = center + (m_TempVerts[2].position - center) * scale;
            m_TempVerts[3].position = center + (m_TempVerts[3].position - center) * scale;
        }

        void ModifyTempVertsColor(Color color)
        {
            m_TempVerts[0].color = color;
            m_TempVerts[1].color = color;
            m_TempVerts[2].color = color;
            m_TempVerts[3].color = color;
        }

        void ModifyTempVertsUV(Sprite spr, float texIndex, float fixRatio, EAxis flip)
        {
            Vector4 uv = DataUtility.GetOuterUV(spr);
            //m_TempVerts[0].uv0 = new Vector2(uv.x, uv.w) - duv;
            //m_TempVerts[1].uv0 = new Vector2(uv.z, uv.w) - duv;
            //m_TempVerts[2].uv0 = new Vector2(uv.z, uv.y) - duv;
            //m_TempVerts[3].uv0 = new Vector2(uv.x, uv.y) - duv;
            if (flip == EAxis.X)
            {
                var f = uv.x;
                uv.x = uv.z;
                uv.z = f;
            }
            else if (flip == EAxis.Y)
            {
                var f = uv.y;
                uv.y = uv.w;
                uv.w = f;
            }

            var vert0 = m_TempVerts[0];
            vert0.uv0 = new Vector4(uv.x, uv.w, 0, texIndex);

            var vert1 = m_TempVerts[1];
            vert1.uv0 = new Vector4(uv.z, uv.w, 0, texIndex);

            var vert2 = m_TempVerts[2];
            vert2.uv0 = new Vector4(uv.z, uv.y, 0, texIndex);

            var vert3 = m_TempVerts[3];
            vert3.uv0 = new Vector4(uv.x, uv.y, 0, texIndex);

            if (!Mathf.Approximately(fixRatio, 0))
            {
                float ratio;
                if (fixRatio > 0)
                {
                    ratio = fixRatio;
                }
                else
                {
                    var texsize = spr.rect.size;
                    ratio = texsize.x / texsize.y;
                }
                var size = vert1.position - vert3.position;
                var center = vert3.position + (Vector3)size * 0.5f;
                center.y -= size.y * mFixEmojiVerticle;
                var ratio2 = size.x / size.y;
                if (ratio > ratio2)
                {
                    size.y = size.x / ratio;
                    //center.y = vert3.position.y + size.y * 0.5f;
                }
                else
                {
                    size.x = size.y * ratio;
                }
                size *= 0.5f;
                vert0.position = center + new Vector3(-size.x, size.y, 0);
                vert1.position = center + new Vector3(size.x, size.y, 0);
                vert2.position = center + new Vector3(size.x, -size.y, 0);
                vert3.position = center + new Vector3(-size.x, -size.y, 0);
            }

            m_TempVerts[0] = vert0;
            m_TempVerts[1] = vert1;
            m_TempVerts[2] = vert2;
            m_TempVerts[3] = vert3;
        }

        void SetupSprite(/*Material mat, */Sprite spr, ref Texture2D tex1, ref Texture2D tex2, out int texIndex)
        {
            if (tex1 == null)
            {
                tex1 = spr.texture;
                //mat.SetTexture(mTexId, tex1);
                texIndex = 1;
                //duv = new Vector2(10f, 10f);
            }
            else if (tex1 == spr.texture)
            {
                texIndex = 1;
                //duv = new Vector2(10f, 10f);
            }
            else if (tex2 == null)
            {
                tex2 = spr.texture;
                //mat.SetTexture(mTexId2, tex2);
                texIndex = 2;
                //duv = new Vector2(20f, 20f);
            }
            else
            {
                texIndex = 2;
                //duv = new Vector2(20f, 20f);
            }
        }

        Vector2 GetAnchor()
        {
            Vector2 anchor;
            switch (alignment)
            {
                case TextAnchor.UpperLeft:
                    anchor = new Vector2(0f, 1f);
                    break;
                case TextAnchor.UpperCenter:
                    anchor = new Vector2(0.5f, 1f);
                    break;
                case TextAnchor.UpperRight:
                    anchor = new Vector2(1f, 1f);
                    break;
                case TextAnchor.MiddleLeft:
                    anchor = new Vector2(0f, 0.5f);
                    break;
                case TextAnchor.MiddleCenter:
                    anchor = new Vector2(0.5f, 0.5f);
                    break;
                case TextAnchor.MiddleRight:
                    anchor = new Vector2(1f, 0.5f);
                    break;
                case TextAnchor.LowerLeft:
                    anchor = new Vector2(0f, 0f);
                    break;
                case TextAnchor.LowerCenter:
                    anchor = new Vector2(0.5f, 0f);
                    break;
                case TextAnchor.LowerRight:
                    anchor = new Vector2(1f, 0f);
                    break;
                default:
                    anchor = Vector2.zero;
                    break;
            }
            return anchor;
        }

        // endPos: right-down pos
        void FixSymbolChar(float xmin, float threshold, ref float lineheight, ref Vector3 endPos, ref bool newline, ref float xoffset)
        {
            if (threshold > 0.8f)
                return;
            if (newline)
            {
                newline = false;
                xoffset = Mathf.Min(xmin, m_TempVerts[0].position.x + xoffset) - m_TempVerts[0].position.x;
            }
            var h = m_TempVerts[0].position.y - m_TempVerts[2].position.y;
            if (h > lineheight)
            {
                lineheight = h;
                if (xoffset < -0.1f)
                    MoveTempVerts(new Vector3(xoffset, 0, 0));
                endPos = m_TempVerts[2].position;
                return;
            }
            var line = m_TempVerts[2].position.y;
            if (line > endPos.y - lineheight)
            {
                if (xoffset < -0.1f)
                    MoveTempVerts(new Vector3(xoffset, 0, 0));
                endPos = m_TempVerts[2].position;
                return;
            }
            if (h > lineheight * threshold)
            {
                xoffset = 0;
                endPos = m_TempVerts[2].position;
                return;
            }
            var offset = endPos - m_TempVerts[3].position;
            endPos = m_TempVerts[2].position;
            xoffset = m_TempVerts[0].position.x - endPos.x;
            MoveTempVerts(offset);
            endPos.x += xoffset;
            lineheight = 0;
            newline = true;
        }

        protected override void OnPopulateMesh(VertexHelper toFill)
        {
            //mHasSprite = false;
            //if (!m_SupportEmoji)
            //{
            //    base.OnPopulateMesh(toFill);
            //    return;
            //}
            if (font == null)
                return;

            Vector2 anchor = GetAnchor();

            m_DisableFontTextureRebuiltCallback = true;

            //Material mat = materialForRendering;
            //Texture2D tex1 = null;
            //Texture2D tex2 = null;

            int emojIndex = 0;
            //Emoji emoj = mEmojies.Count > 0 ? mEmojies[emojIndex] : default(Emoji);

            Vector2 extents = rectTransform.rect.size;
            var settings = GetGenerationSettings(extents);
            cachedTextGenerator.PopulateWithErrors(text, settings, gameObject);
            // Apply the offset to the vertices
            IList<UIVertex> verts = cachedTextGenerator.verts;
            float unitsPerPixel = 1 / pixelsPerUnit;
            //Last 4 verts are always a new line... (\n)
            int vertCount = verts.Count; // - 4;

            // a character height
            float lineheight = 0;
            Vector3 endPos = Vector3.zero;
            float xoffset = 0;
            var fixthreshold = (1 << (int)m_FixSymbolLevel) * 0.15f;
            Vector2 roundingOffset = verts.Count == 0 ? Vector2.zero : new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel;
            roundingOffset = PixelAdjustPoint(roundingOffset) - roundingOffset;
            toFill.Clear();

            float xmin;
            bool newline = false;
            if (vertCount > 0)
            {
                var p0 = verts[0].position;
                p0 *= unitsPerPixel;
                xmin = p0.x + extents.x * anchor.x;
            }
            else
            {
                xmin = 0;
            }

            if (roundingOffset != Vector2.zero)
            {
                for (int i = 0; i < vertCount; ++i)
                {
                    int tempVertsIndex = i & 3;
                    m_TempVerts[tempVertsIndex] = verts[i];
                    m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                    m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
                    m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
                    if (tempVertsIndex == 3)
                    {
                        FixSymbolChar(xmin, fixthreshold, ref lineheight, ref endPos, ref newline, ref xoffset);
                        toFill.AddUIVertexQuad(m_TempVerts);
                    }
                }
            }
            else
            {
                //float texIndex;
                for (int i = 0; i < vertCount; ++i)
                {
                    int tempVertsIndex = i & 3;
                    m_TempVerts[tempVertsIndex] = verts[i];
                    m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                    if (tempVertsIndex == 3)
                    {
                        var deltauv = m_TempVerts[0].uv0 - m_TempVerts[2].uv0;
                        bool isEmoji = m_SupportEmoji && (Mathf.Abs(deltauv.x) >= 0.9f || Mathf.Abs(deltauv.y) >= 0.9f);
                        if (!isEmoji)
                        {
                            FixSymbolChar(xmin, fixthreshold, ref lineheight, ref endPos, ref newline, ref xoffset);
                            toFill.AddUIVertexQuad(m_TempVerts);
                        }
                        // as quad
                        else if (emojIndex < mEmojies.Count)
                        {
                            FixSymbolChar(xmin, fixthreshold, ref lineheight, ref endPos, ref newline, ref xoffset);
                            var index = emojIndex++;
                            var emoj = mEmojies[index];
                            //mHasSprite = true;
                            Sprite spr = emoj.result.sprite;// GetSprite(sprName);
                            if (spr != null)
                            {
                                //SetupSprite(spr, ref tex1, ref tex2, out texIndex);
                                ModifyTempVertsUV(spr, emoj.result.texIndex, emoj.fixRatio, emoj.flip);
                                if (!Mathf.Approximately(emoj.scale, 1))
                                {
                                    ScaleTempVerts(anchor, emoj.scale);
                                }
                                if (Mathf.Abs(emoj.finalRotate) > 0.1)
                                {
                                    RotateTempVerts(emoj.finalRotate);
                                }
                                if (emoj.offset.sqrMagnitude > 0.01)
                                {
                                    var offset = (Vector3)emoj.offset;
                                    if (Mathf.Abs(offset.x) < 1)
                                        offset.x = Mathf.Abs(m_TempVerts[2].position.x - m_TempVerts[0].position.x) * offset.x;
                                    if (Mathf.Abs(offset.y) < 1)
                                        offset.y = Mathf.Abs(m_TempVerts[2].position.y - m_TempVerts[0].position.y) * offset.y;
                                    MoveTempVerts(offset);
                                }
                                if (emoj.raw)
                                {
                                    var col = Color.white;
                                    col.a = color.a;
                                    ModifyTempVertsColor(col);
                                }

                                var btn = GetEmojiBtn(emoj, index);
                                if (btn != null)
                                {
                                    btn.rect = CalculateTempVertsBounds();
                                }
                                toFill.AddUIVertexQuad(m_TempVerts);
                            }
                        }
                    }
                }
            }

            m_DisableFontTextureRebuiltCallback = false;
        }

        private void Update()
        {
            if (mAnimate)
            {
                mTimer += Time.deltaTime;
                mTime += Time.deltaTime;
                if (mTimer >= mAnimDuration)
                {
                    mTimer -= mAnimDuration;
                    //SetVerticesDirty();
                    GetEmojiResultsDirty();
                }
            }
        }

        public int GetBtnId(Vector2 screenPoint)
        {
            var can = canvas;
            if (can == null)
                return 0;
            Vector2 point;
            var raypoint = RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, can.worldCamera, out point);
            if (raypoint)
            {
                for (int i = 0; i < mEmojiBtns.Count; i++)
                {
                    var btn = mEmojiBtns[i];
                    if (btn.rect.Contains(point))
                    {
                        return btn.clickId;
                    }
                }
            }
            return 0;
        }

#if UNITY_EDITOR
        protected override void OnValidate()
        {
#if SIMULATION
            if (!Application.isPlaying)
#endif
            {
                GetEmojies();
                if (enabled && gameObject.activeInHierarchy)
                    GetEmojiResultsDirty();
            }
            mFixEmojiVerticle = GetFontVerticleFixPercent(font);
            base.OnValidate();
        }

        private void OnDrawGizmosSelected()
        {
            Gizmos.matrix = transform.localToWorldMatrix;
            Gizmos.color = Color.cyan * 0.5f;
            for (int i = 0; i < mEmojiBtns.Count; i++)
            {
                var btn = mEmojiBtns[i];
                GizmosUtil.DrawWiredCube(btn.rect.center, btn.rect.size);
            }
        }

#endif

    }

}